package monitorandwebserver;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

//TODO wszystko, caly web server aktualnie jest niegotowy
public class WebServer extends Thread {

    ArrayList<Integer> ports;
    int currentPortNumber = 7000;
    int subscribtionId = 0;
    HttpServer server;
    private ClientWriterThread clientWriterThreadInstance;

    void setClientWriterThreadInstance(ClientWriterThread cwt) {
        this.clientWriterThreadInstance = cwt;
        
    }

    public WebServer(int port) {
        try {
            ports = new ArrayList<Integer>();
            server = HttpServer.create(new InetSocketAddress(port), 0);
            server.createContext("/subscribtions", new ConnectSubscribtionHandler());
            //server.createContext("/test", new TestHandler());
            server.setExecutor(null); // creates a default executor
            server.start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


    class ConnectSubscribtionHandler implements HttpHandler {

        public void handle(HttpExchange t) throws IOException {
            //get request data from client
            String line;
            BufferedReader in = new BufferedReader(new InputStreamReader(t.getRequestBody()));
            line = in.readLine();
            String[] lines;
            lines = line.split("&");
            String metric = lines[0].substring(7);
            String resourceId = lines[1].substring(11);
            System.out.println("Client " + t.getRemoteAddress().getHostName() + ":" + t.getRemoteAddress().getPort() + " requested: " + metric + " of resource: " + resourceId);
            //check if requested resource exists in system
            //create virtual connection for client
            subscribtionId++;
            String response = "http://127.0.0.1:8080/subscribtions/" + subscribtionId + "\n";
            server.createContext("/subscribtions/"+subscribtionId+"", new NewSubscribtionHandler(subscribtionId));//TODO jesli wywwala exceptiona może handler musi być static
            clientWriterThreadInstance.addVirtualConnection(subscribtionId, new NetworkAddress(t.getRemoteAddress().getHostName(),t.getRemoteAddress().getPort()), resourceId,metric);
            t.sendResponseHeaders(201, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    class NewSubscribtionHandler implements HttpHandler {

        int id;

        public NewSubscribtionHandler(int id) {
            this.id = id;
        }

        public void handle(HttpExchange t) throws IOException {
            
            if(t.getRequestMethod().equals("DELETE")){
                
                //BufferedReader in = new BufferedReader(new InputStreamReader(t.getRequestBody()));
                String line = t.getRequestURI().toASCIIString();

                String response = "";
                t.sendResponseHeaders(200, response.length());
                OutputStream os = t.getResponseBody();
                os.write(response.getBytes());
                os.close();
                server.removeContext(line);
            }else{
            String line;
            BufferedReader in = new BufferedReader(new InputStreamReader(t.getRequestBody()));
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }

            //will look for a free port to bind socket to
            ServerSocket serverSocket = createSocket();

            String response = "<host>127.0.0.1</host>\n";
            response += "<port>" + serverSocket.getLocalPort() + "</port>";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();

            Socket clientSocket = serverSocket.accept();
            clientWriterThreadInstance.establishConnection(clientSocket, id);
            }
            
        }
    }

    public int generateUniquePortNumber() {
        currentPortNumber++;
        boolean hasDuplicate = false;
        while (hasDuplicate) {
            hasDuplicate = false;
            for (int i = 0; i < ports.size(); i++) {
                if (currentPortNumber == ports.get(i)) {
                    hasDuplicate = true;
                    currentPortNumber++;
                    if (currentPortNumber > 7999) {
                        currentPortNumber = 7000;
                    }
                    break;
                }
            }
        }
        return currentPortNumber;
    }

    //will look for free port (unbound by other monitors)
    public ServerSocket createSocket() throws IOException {
        while (true) {
            int port = generateUniquePortNumber();
            try {
                return new ServerSocket(port);
            } catch (IOException ex) {
                continue; // try next port
            }
        }

    }
}

